package jys.test.yddata.utils;

import android.Manifest;
import android.annotation.SuppressLint;
import android.util.Log;
import android.util.Size;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.core.UseCaseGroup;
import androidx.camera.core.ViewPort;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

public class CameraManager {
    private AppCompatActivity app;
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private CameraSelector cameraSelector;
    private ImageCapture imageCapture;
    private PreviewView previewView;
    private Preview preview;
    private Executor executor = Executors.newSingleThreadExecutor();

    private BooleanSupplier startLoading;
    private Consumer<ImageCapture.OutputFileResults> captureCall;
    private Consumer<Boolean> endLoading;
    private Consumer<String> seriousError;

    /**
     * 初始化相机管理类
     * @param appCompatActivity APP主界面
     * @param previewView 预览视图
     * @param capture_size 照片尺寸，可以为 null
     * @param seriousError 界面错误处理函数
     */
    private CameraManager(@NonNull AppCompatActivity appCompatActivity,
                          @NonNull PreviewView previewView,
                          @NonNull Size capture_size,
                          Consumer<String> seriousError) {
        app = appCompatActivity;
        this.previewView = previewView;
        this.seriousError = seriousError;

        if (!ActivityCompat.shouldShowRequestPermissionRationale(app, Manifest.permission.CAMERA))
            ActivityCompat.requestPermissions(app, new String[]{Manifest.permission.CAMERA},0);

        cameraProviderFuture = ProcessCameraProvider.getInstance(app);
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                bindPreview(app, cameraProvider, capture_size);
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
                if (seriousError != null)
                    seriousError.accept("CameraManager: "+e.getMessage());
                app.runOnUiThread(()-> new AlertDialog.Builder(app)
                        .setTitle("错误")
                        .setMessage("相机启动失败，Exp ["+e.getMessage()+"]")
                        .setPositiveButton("退出", (dialog, which)-> app.finish())
                        .show());
            } catch (Exception e) {
                e.printStackTrace();
                if (seriousError != null)
                    seriousError.accept("CameraManager: "+e.getMessage());
            }
        }, ContextCompat.getMainExecutor(app));
    }

    private void bindPreview(LifecycleOwner lifecycleOwner, @NonNull ProcessCameraProvider cameraProvider, Size capture_size) throws Exception {
        preview = new Preview.Builder()
                .build();
        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        if ( capture_size == null )
            imageCapture = new ImageCapture.Builder()
                    .build();
        else
            imageCapture = new ImageCapture.Builder()
                    .setTargetResolution(capture_size)
                    .build();

        ViewPort vp = previewView.getViewPort();
        if (vp == null) {
            Log.println(Log.WARN, "previewView.getViewPort()", "加载为NULL，请将本类构建方法放置于PreviewView.post方法中");
            throw new Exception("[固件问题，请联系开发者查看日志] previewView.getViewPort() 加载为NULL");
        }

        UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
                .addUseCase(preview)
                .addUseCase(imageCapture)
                .setViewPort(Objects.requireNonNull(vp))
                .build();

        cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);
    }

    /**
     * 设置拍照功能
     * @param captureOnClickEvent 拍照按钮
     * @param startLoading 开始加载函数
     * @param captureCall 照片处理函数
     * @param endLoading 停止加载函数
     */
    private void initCapture(
            View captureOnClickEvent,
            BooleanSupplier startLoading,
            Consumer<ImageCapture.OutputFileResults> captureCall,
            Consumer<Boolean> endLoading)
    {
        this.startLoading = startLoading;
        this.captureCall = captureCall;
        this.endLoading = endLoading;
        captureOnClickEvent.setOnClickListener(this::capture);
    }

    @SuppressLint("Assert")
    private void capture(View v) {
        if(startLoading.getAsBoolean())
            try {
                File cacheFile = new File(app.getBaseContext().getCacheDir().getPath()+"/FIG.jpg");
                assert cacheFile.createNewFile();
                ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(cacheFile).build();
                imageCapture.takePicture(outputFileOptions, executor,
                        new ImageCapture.OnImageSavedCallback() {
                            @Override
                            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                                captureCall.accept(outputFileResults);
                                app.runOnUiThread(()->endLoading.accept(true));
                            }
                            @Override public void onError(@NonNull ImageCaptureException exception) { }
                        }
                );
            } catch (IOException e) {
                e.printStackTrace();
                app.runOnUiThread(()->{
                    Toast.makeText(app, "拍照失败，无法创建缓存文件", Toast.LENGTH_SHORT).show();
                    endLoading.accept(false);
                });
            }
    }

    public static class Builder {
        private boolean inited = false;
        private CameraManager cameraManager;

        public Builder init(@NonNull AppCompatActivity appCompatActivity,
                            @NonNull PreviewView previewView,
                            @NonNull Size capture_size,
                            Consumer<String> seriousError) {
            inited = true;
            cameraManager = new CameraManager(appCompatActivity, previewView, capture_size, seriousError);
            return this;
        }

        @SuppressLint("Assert")
        public CameraManager build() {
            assert inited;
            return cameraManager;
        }

        @SuppressLint("Assert")
        public Builder initCapture(
                View captureOnClickEvent,
                BooleanSupplier startLoading,
                Consumer<ImageCapture.OutputFileResults> captureCall,
                Consumer<Boolean> endLoading) {
            assert inited;
            cameraManager.initCapture(captureOnClickEvent, startLoading, captureCall, endLoading);
            return this;
        }
    }
}
